package com.opennews.openplatform.familyexpenseapi.service

import com.opennews.openplatform.familyexpenseapi.entity.Tables.ROLE
import com.opennews.openplatform.familyexpenseapi.entity.tables.records.RoleRecord
import com.opennews.openplatform.familyexpenseapi.jooq.DSLContextWrapper
import com.opennews.openplatform.familyexpenseapi.jooq.RecordHelper
import com.opennews.openplatform.myspringbootcore.common.constant.ROLE_ACCOUNT_GROUP_ADMIN
import com.opennews.openplatform.myspringbootcore.common.constant.ROLE_ACCOUNT_GROUP_USER
import com.opennews.openplatform.myspringbootcore.common.constant.ROLE_ACCOUNT_GROUP_VIEWER
import com.opennews.openplatform.myspringbootcore.common.constant.ROLE_SYSTEM_ADMIN
import org.jooq.DSLContext
import org.springframework.stereotype.Service

@Service
class RoleService(
    private val dslContext: DSLContext,
    private val dslContextWrapper: DSLContextWrapper,
) {
    /**
     * Prepares the initial data for Role.
     */
    fun init() {
        if (!dslContextWrapper.exists(ROLE)) {
            val records = mutableListOf<RoleRecord>().apply {
                add(
                    createRecord(
                        authority = ROLE_SYSTEM_ADMIN,
                        title = "系统管理员",
                        description = "当前整个系统的管理员，不属于任何账户。",
                    )
                )

                add(
                    createRecord(
                        authority = ROLE_ACCOUNT_GROUP_ADMIN,
                        title = "账户管理员",
                        description = "可对当前账户组下的各项，如银行卡片和收支类别等进行管理。",
                    )
                )

                add(
                    createRecord(
                        authority = ROLE_ACCOUNT_GROUP_USER,
                        title = "用户",
                        description = "账户组普通用户",
                    )
                )

                add(
                    createRecord(
                        authority = ROLE_ACCOUNT_GROUP_VIEWER,
                        title = "查看者",
                        description = "账户组只读用户，仅可查看，不可操作数据。",
                    )
                )
            }

            dslContext.batchInsert(records)
        }
    }

    /**
     * Queries the role ID by authority.
     *
     * @param authority The authority (role name) to search for.
     * @return The role ID if found, otherwise null.
     */
    fun queryId(authority: String): String? =
        dslContext.selectFrom(ROLE)
            .where(ROLE.AUTHORITY.eq(authority))
            .fetchOne(ROLE.ID)

    /**
     * Queries non-system level roles with their ID, authority, title, and description.
     *
     * @return A list of maps where each map contains:
     *         - `id`: The role ID as a String.
     *         - `authority`: The role authority (i.e., role name) as a String.
     *         - `title`: The role title as a String.
     *         - `description`: The role description as a String.
     */
    fun queryNonSystemLevelRoles(): List<Map<String, Any>> {
        // All system level roles which will be ignored from this result.
        val systemRoles = listOf(ROLE_SYSTEM_ADMIN)

        return dslContext
            .select(
                ROLE.ID.`as`("id"),
                ROLE.AUTHORITY.`as`("authority"),
                ROLE.TITLE.`as`("title"),
                ROLE.DESCRIPTION.`as`("description"),
            )
            .from(ROLE)
            .where(ROLE.AUTHORITY.notIn(systemRoles))
            .fetchMaps()
    }

    /**
     * Queries all roles, retrieving their IDs and titles.
     *
     * @return A list of maps where each map contains:
     *         - `id`: The role ID as a String.
     *         - `title`: The role title as a String.
     */
    fun queryAllRoles(): List<Map<String, Any>> =
        dslContext
            .select(
                ROLE.ID.`as`("id"),
                ROLE.TITLE.`as`("title"),
            )
            .from(ROLE)
            .fetchMaps()

    /**
     * Counts the number of roles that match the specified role IDs and authority.
     *
     * @param ids A list of role IDs to filter by.
     * @param authority The authority (role name) to filter by.
     * @return The count of matching roles.
     */
    fun countByRoleIdsAndAuthority(ids: List<String>, authority: String): Int =
        dslContextWrapper.count(ROLE, ROLE.ID.`in`(ids).and(ROLE.AUTHORITY.eq(authority)))

    private fun createRecord(authority: String, title: String, description: String): RoleRecord {
        return dslContext.newRecord(ROLE).apply {
            RecordHelper.setCommonFields(this)
            this.authority = authority
            this.title = title
            this.description = description
        }
    }
}